<?php

    class WZ_Application
    {
        public $_reg;
        static $_instance;
		
		// singleton
		public static function &getInstance($dispatch = true) 
		{
            if (!self::$_instance instanceof self) {
				self::$_instance = new self($dispatch);
			}
            return self::$_instance;
		}
        
        public function __construct($dispatch = true)
        {
            if (true === $dispatch) {
                $confApp = new \Zend_Config_Ini(
                    APPLICATION_PATH . "/configs/" . APPLICATION_ENV . ".ini"
                );
                $confRoutes = new \Zend_Config_Ini(
                    APPLICATION_PATH . "/configs/routes.ini"
                );
                
                \WZ::set('confApp', new WZ_Config('confApp', $confApp->toArray()));
                \WZ::set('confRoutes', new WZ_Config('confRoutes', $confRoutes->toArray()));
                $bootstrap = new WZ_Bootstrap();
                $bootstrap->run();
                self::dispatch();
            }
        }
        
        public static function execMethods($class, $methods)
        {
            foreach ($methods as $value => $method) {
                $class->$method();
            }
        }
        
        public static function dispatch($return = false)
        {
            \WZ::set('WZApp', \WZ_Application::getInstance(false));
            \WZ::set('isCached', false);
            $continue = true;
            $error = false;
            
            $route = \WZ_Route::getInstance();
            
            $module = $route->getModule();
            $controller = $route->getController();
            $action = $route->getAction();
            
            $moduleBootstrapName = ucfirst(strtolower($module)) . 'Bootstrap';
            $moduleBootstrap = APPLICATION_PATH . '/modules/' . $module . '/' . $moduleBootstrapName . '.php';
            
            if (file_exists($moduleBootstrap)) {
                require_once $moduleBootstrap;
            } else {
                self::is404();
                $continue = false;
            }
            if (true === $continue) {
                $moduleBootstrapInstance = new $moduleBootstrapName;
                $methodsModuleBootstrap = $moduleBootstrapInstance->getClassResources();
                self::execMethods($moduleBootstrapInstance, $methodsModuleBootstrap);
                
                $controllerName = ucfirst(strtolower($controller)) . 'Controller';
                $controllerNameInstance = ucfirst(strtolower($module)) . '_' . ucfirst(strtolower($controller)) . 'Controller';
                $controllerPath = APPLICATION_PATH . '/modules/' . $module . '/controllers/' . $controllerName . '.php';
                if (file_exists($controllerPath)) {
                    require_once $controllerPath;
                } else {
                    self::is404();
                    $continue = false;
                }
                if (true === $continue) {
                    $controllerInstance = new $controllerNameInstance;
                    
                    $methodsController = $controllerInstance->getClassResources();
                    self::execMethods($controllerInstance, $methodsController);
                    
                    $methodsController = get_class_methods($controllerInstance);
                    $actionName = $action . 'Action';
                    
                    if(!in_array($actionName, $methodsController)) {
                        self::is404();
                        $continue = false;
                    }
                    if (true === $continue) {
                        $viewName = strtolower($controller);
                        $viewPath = APPLICATION_PATH . '/modules/' . $module . '/views/scripts/' . $controller . '/' . $action . '.phtml';
                        $zviewPath = $controller . '/' . $action . '.phtml';
                        if (in_array('preDispatch', $methodsController)) {
                            $controllerInstance->preDispatch();
                        }
                        @$controllerInstance->$actionName();
                        $isCached = \WZ::get('isCached');
                        if (true === $isCached) {
                            $hash = md5($controller . $action . $module . implode(',', $route->params));
                            $cacheManager = \WZ::get('WZCacheView');
                            if (!($render = $cacheManager->load($hash))) {
                                $zview = new \WZ_View();
                                $view = $controllerInstance->view;
                                \WZ::set('WZView', $view);
                                $zview->app = \WZ_Application::getInstance(false);
                                \WZ::set('WZApp', \WZ_Application::getInstance(false));
                                
                                if (null !== $view && $view instanceof stdclass) {
                                    foreach ($view as $key => $value) {
                                        $zview->$key = $value;
                                    }
                                }
                                if (null !== $route->params && count($route->params)) {
                                    foreach ($route->params as $key => $value) {
                                        $zview->$key = $value;
                                    }
                                }
                                $zview->setBasePath(APPLICATION_PATH . '/modules/' . $module . '/views');
                                $render = $zview->render($zviewPath);
                                $cacheManager->save($render, $hash);
                                if (true === $return) {
                                    if (in_array('postDispatch', $methodsController)) {
                                        $controllerInstance->postDispatch();
                                    }
                                    return $render;
                                } else {
                                    echo $render;
                                    if (in_array('postDispatch', $methodsController)) {
                                        $controllerInstance->postDispatch();
                                    }
                                }
                            } else {
                                if (true === $return) {
                                    if (in_array('postDispatch', $methodsController)) {
                                        $controllerInstance->postDispatch();
                                    }
                                    return $render;
                                } else {
                                    echo $render;
                                    if (in_array('postDispatch', $methodsController)) {
                                        $controllerInstance->postDispatch();
                                    }
                                }
                            }
                        } else {
                            $zview = new \WZ_View();
                            $view = $controllerInstance->view;
                            \WZ::set('WZView', $view);
                            if (null !== $view && $view instanceof stdclass) {
                                foreach ($view as $key => $value) {
                                    $zview->$key = $value;
                                }
                            }
                            if (null !== $route->params && count($route->params)) {
                                foreach ($route->params as $key => $value) {
                                    $zview->$key = $value;
                                }
                            }
                            $zview->app = \WZ_Application::getInstance(false);
                            \WZ::set('WZApp', \WZ_Application::getInstance(false));
                            $zview->setBasePath(APPLICATION_PATH . '/modules/' . $module . '/views');
                            $render = $zview->render($zviewPath);
                            if (null !== \WZ::get('WZError') && true !== \WZ::get('WZIsError')) {
                                self::isError();
                            } else {
                                if (true === $return) {
                                    if (in_array('postDispatch', $methodsController)) {
                                        $controllerInstance->postDispatch();
                                    }
                                    return $render;
                                } else {
                                    echo $render;
                                    if (in_array('postDispatch', $methodsController)) {
                                        $controllerInstance->postDispatch();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        
        public function action($controller, $action, $module, $args = array())
        {
            $route = \WZ_Route::getInstance();
            $route->setModule($module);
            $route->setController($controller);
            $route->setAction($action);
            if (count($args)) {
                foreach ($args as $key => $value) {
                    $route->setParam($key, $value);
                }
            }
            return self::dispatch(true);
        }
        
        public function partial($partial, $args = array(), $cache = false, $return = false)
        {
            $route = \WZ_Route::getInstance();
            $module = $route->getModule();
            $view = \WZ::get('WZView');
            if (count($args)) {
                foreach ($args as $key => $value) {
                    $view->$key = $value;
                }
            }
            if (true === $cache) {
                self::cached();
                $hash = md5($partial . implode(',', $args));
                $cacheManager = \WZ::get('WZCacheView');
                if (!($render = $cacheManager->load($hash))) {
                    $this->view = $zview = new \WZ_View();
                    \WZ::set('WZView', $view);
                    $zview->app = $app = \WZ_Application::getInstance(false);                    
                    \WZ::set('WZApp', $app);
                    if (null !== $view && $view instanceof stdclass) {
                        foreach ($view as $key => $value) {
                            $zview->$key = $value;
                        }
                    }
                    $zview->setBasePath(APPLICATION_PATH . '/modules/' . $module . '/views');
                    $zpartialPath = 'partials/' . $partial;
                    $render = $zview->render($zpartialPath);
                    $cacheManager->save($render, $hash);
                    if (false === $return) {
                        echo $render;
                    } else {
                        return $render;
                    }
                } else {
                    if (false === $return) {
                        echo $render;
                    } else {
                        return $render;
                    }
                }
            } else {
                $this->view = $zview = new \WZ_View();
                \WZ::set('WZView', $view);
                $zview->app = $app = \WZ_Application::getInstance(false);
                \WZ::set('WZApp', $app);
                if (null !== $view && $view instanceof stdclass) {
                    foreach ($view as $key => $value) {
                        $zview->$key = $value;
                    }
                }
                $zview->setBasePath(APPLICATION_PATH . '/modules/' . $module . '/views');
                $zpartialPath = 'partials/' . $partial;
                $render = $zview->render($zpartialPath);
                if (false === $return) {
                    echo $render;
                } else {
                    return $render;
                }
            }
        }
        
        public static function is404()
        {
            $routes = \WZ::get('confRoutes')->confRoutes;
            $route = \WZ_Route::getInstance();
            $route->setModule($routes['www_404']['defaults']['module']);
            $route->setController($routes['www_404']['defaults']['controller']);
            $route->setAction($routes['www_404']['defaults']['action']);
            $route->setFormat($routes['www_404']['defaults']['format']);
            self::dispatch();
        }
        
        public static function isError()
        {
            $routes = \WZ::get('confRoutes')->confRoutes;
            $route = \WZ_Route::getInstance();
            $route->setModule($routes['www_error']['defaults']['module']);
            $route->setController($routes['www_error']['defaults']['controller']);
            $route->setAction($routes['www_error']['defaults']['action']);
            $route->setFormat($routes['www_error']['defaults']['format']);
            \WZ::set('WZIsError', true);
            self::dispatch();
        }
        
        public function cached($ttl = 7200)
        {            
            $dbCache = DIR_CACHE . 'cacheView.db';
            $frontendOptions = array(
                'caching' => true,
                'lifetime' => $ttl,
                'automatic_serialization' => true
            );
            
            $cacheView = \Zend_Cache::factory (
                'Core',
                'Sqlite',
                $frontendOptions,
                array ('cache_db_complete_path' => $dbCache)
            );
            
            $cache = new \WZ_Cache($cacheView);
            
            \WZ::set('WZCacheView', $cacheView);
            \WZ::set('isCached', true);
        }
    }